<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="renderer" content="webkit"><meta name="format-detection" content="telephone=no"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="icon" href="/images/icons/favicon-16x16.png?v=2.0.0-rc.0" type="image/png" sizes="16x16"><link rel="icon" href="/images/icons/favicon-32x32.png?v=2.0.0-rc.0" type="image/png" sizes="32x32"><meta name="description" content="一、环境准备        linux系统，本人使用的是centos8，最小化安装">
<meta property="og:type" content="article">
<meta property="og:title" content="Docker学习">
<meta property="og:url" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/index.html">
<meta property="og:site_name" content="孙宇的博客">
<meta property="og:description" content="一、环境准备        linux系统，本人使用的是centos8，最小化安装">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/1.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/2.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/3.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/4.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/5.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/6.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/7.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/8.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/9.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/10.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/11.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/15.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/12.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/13.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/19.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/20.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/21.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/22.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/23.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/24.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/25.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/26.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/27.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/28.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/29.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/30.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/31.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/32.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/33.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/34.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/35.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/36.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/37.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/38.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/39.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/40.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/41.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/42.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/43.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/44.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/51.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/45.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/46.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/47.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/48.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/49.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/50.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/52.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/53.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/54.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/55.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/56.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/56.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/58.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/59.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/60.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/61.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/62.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/63.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/64.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/65.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/66.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/67.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/67.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/14.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/16.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/17.png">
<meta property="og:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/18.png">
<meta property="article:published_time" content="2021-08-26T10:07:36.000Z">
<meta property="article:modified_time" content="2021-09-11T02:18:34.891Z">
<meta property="article:author" content="孙宇">
<meta property="article:tag" content="Docker">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/1.png"><meta name="keywords" content="孙宇, 孙宇的博客"><meta name="description" content=""><title>Docker学习 | 孙宇的博客</title><link ref="canonical" href="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/"><link rel="dns-prefetch" href="https://cdn.jsdelivr.net"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.12.1/css/all.min.css" type="text/css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gitalk@latest/dist/gitalk.min.css" type="text/css"><link rel="stylesheet" href="/css/index.css?v=2.0.0-rc.0"><script>var Stun = window.Stun || {};
var CONFIG = {
  root: '/',
  algolia: undefined,
  fontIcon: {"prompt":{"success":"fas fa-check-circle","info":"fas fa-arrow-circle-right","warning":"fas fa-exclamation-circle","error":"fas fa-times-circle"},"copyBtn":"fas fa-copy"},
  sidebar: {"offsetTop":"20px","tocMaxDepth":6},
  header: {"enable":true,"showOnPost":true,"scrollDownIcon":true},
  postWidget: {"endText":true},
  nightMode: {"enable":true},
  back2top: {"enable":true},
  codeblock: {"style":"default","highlight":"light","wordWrap":false},
  reward: false,
  fancybox: false,
  zoomImage: {"gapAside":"20px"},
  galleryWaterfall: undefined,
  lazyload: false,
  pjax: undefined,
  externalLink: {"icon":{"enable":true,"name":"fas fa-external-link-alt"}},
  shortcuts: {"switchPost":true},
  prompt: {"copyButton":"复制","copySuccess":"复制成功","copyError":"复制失败"},
  sourcePath: {"js":"js","css":"css","images":"images"},
};

window.CONFIG = CONFIG;</script><meta name="generator" content="Hexo 5.0.2"></head><body><div class="container" id="container"><header class="header" id="header"><div class="header-inner"><nav class="header-nav header-nav--fixed"><div class="header-nav-inner"><div class="header-nav-menubtn"><i class="fas fa-bars"></i></div><div class="header-nav-menu"><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/"><span class="header-nav-menu-item__icon"><i class="fas fa-home"></i></span><span class="header-nav-menu-item__text">首页</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/archives/"><span class="header-nav-menu-item__icon"><i class="fas fa-folder-open"></i></span><span class="header-nav-menu-item__text">归档</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/categories/"><span class="header-nav-menu-item__icon"><i class="fas fa-layer-group"></i></span><span class="header-nav-menu-item__text">分类</span></a></div><div class="header-nav-menu-item"><a class="header-nav-menu-item__link" href="/tags/"><span class="header-nav-menu-item__icon"><i class="fas fa-tags"></i></span><span class="header-nav-menu-item__text">标签</span></a></div></div><div class="header-nav-search"><span class="header-nav-search__icon"><i class="fas fa-search"></i></span><span class="header-nav-search__text">搜索</span></div><div class="header-nav-mode"><div class="mode"><div class="mode-track"><span class="mode-track-moon"></span><span class="mode-track-sun"></span></div><div class="mode-thumb"></div></div></div></div></nav><div class="header-banner"><div class="header-banner-info"><div class="header-banner-info__title">孙宇的博客</div><div class="header-banner-info__subtitle">博客小白，正在学习中。如果有更好的意见欢迎反馈。</div></div><div class="header-banner-arrow"><div class="header-banner-arrow__icon"><i class="fas fa-angle-down"></i></div></div></div></div></header><main class="main" id="main"><div class="main-inner"><div class="content-wrap" id="content-wrap"><div class="content" id="content"><!-- Just used to judge whether it is an article page--><div id="is-post"></div><div class="post"><header class="post-header"><h1 class="post-title">Docker学习</h1><div class="post-meta"><span class="post-meta-item post-meta-item--createtime"><span class="post-meta-item__icon"><i class="far fa-calendar-plus"></i></span><span class="post-meta-item__info">发表于</span><span class="post-meta-item__value">2021-08-26</span></span><span class="post-meta-item post-meta-item--updatetime"><span class="post-meta-item__icon"><i class="far fa-calendar-check"></i></span><span class="post-meta-item__info">更新于</span><span class="post-meta-item__value">2021-09-11</span></span><span class="post-meta-item post-meta-item--wordcount"><span class="post-meta-item__icon"><i class="far fa-file-word"></i></span><span class="post-meta-item__info">字数统计</span><span class="post-meta-item__value">5k</span></span></div></header><div class="post-body">
        <h1 id="一、环境准备">
          <a href="#一、环境准备" class="heading-link"><i class="fas fa-link"></i></a>一、环境准备</h1>
      <ul>
<li>linux系统，本人使用的是centos8，最小化安装</li>
</ul>
<a id="more"></a>


        <h1 id="二、安装">
          <a href="#二、安装" class="heading-link"><i class="fas fa-link"></i></a>二、安装</h1>
      <ol>
<li><p>下载 <strong>docker</strong> 脚本</p>
<ul>
<li><p>可以通过 <span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://get.docker.com/">get.docker</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span> 下载 <strong>docker</strong> 的安装脚本</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/1.png" alt="图片加载失败"></p>
</li>
<li><p>直接通过 <code>curl -fsSL get.docker.com -o get-docker.sh</code> 命令下载 <strong>docker</strong> 脚本</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/2.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
<li><p>执行脚本</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/3.png" alt="图片加载失败"></p>
</li>
<li><p>验证</p>
<ul>
<li><p>执行 <code>docker version</code> 查看 <strong>docker</strong> 版本</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/4.png" alt="图片加载失败"></p>
<p>在上图中我们可以看到 <strong>docker</strong> 的版本等信息，并且可以看到 <strong>docker</strong> 没有连接。这是因为没有启动 <strong>docker</strong> 的服务</p>
</li>
<li><p>执行 <code>systemctl start docker</code> 启动 <strong>docker</strong> 的服务</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/5.png" alt="图片加载失败"></p>
<p>启动后我们已经可以看到 <strong>docker</strong> 的服务的相关信息了</p>
</li>
</ul>
</li>
</ol>
<p>到这里，<strong>docker</strong> 就已经安装完成了</p>

        <h1 id="三、容器的快速上手">
          <a href="#三、容器的快速上手" class="heading-link"><i class="fas fa-link"></i></a>三、容器的快速上手</h1>
      
        <h2 id="1、docker-的命令行">
          <a href="#1、docker-的命令行" class="heading-link"><i class="fas fa-link"></i></a>1、docker 的命令行</h2>
      <ul>
<li><p>我们可以通过 <code>docker</code> 命令查看都有什么可以执行的命令</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/6.png" alt="图片加载失败"></p>
</li>
<li><p><strong>docer</strong> 命令行的结构:</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker 想要操作的对象</span><br></pre></td></tr></table></div></figure>

<p>例如：</p>
<ul>
<li><p>我们可以输入 <code>docker container --help</code> 查看都有什么可以执行的命令</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/7.png" alt="图片加载失败"></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> 列出当前运行的容器</span></span><br><span class="line">docker container ls</span><br><span class="line"></span><br><span class="line"><span class="meta">#</span><span class="bash"> 列出所有容器</span></span><br><span class="line">docker container ls -a</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>我们也可以输入 <code>docker container ls --help</code> 来查看都有什么参数</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/8.png" alt="图片加载失败"></p>
<p><strong>Aliases：</strong>ls 可以替换成什么</p>
<p><strong>Options：</strong>可以使用的参数选项</p>
</li>
</ul>
</li>
</ul>

        <h2 id="2、docker-的镜像-VS-容器">
          <a href="#2、docker-的镜像-VS-容器" class="heading-link"><i class="fas fa-link"></i></a>2、docker 的镜像 VS 容器</h2>
      
        <h3 id="1-image-镜像">
          <a href="#1-image-镜像" class="heading-link"><i class="fas fa-link"></i></a>1.image 镜像</h3>
      <ul>
<li><strong>Docker image</strong> 是一个 <strong>read only</strong> 文件</li>
<li>这个文件包含文件系统，源码，库文件，依赖，工具等一些运行 <strong>application</strong> 所需要的文件</li>
<li>可以理解成一个模板</li>
<li><strong>Docker image</strong> 具有分层的概念</li>
</ul>

        <h3 id="2-container-容器">
          <a href="#2-container-容器" class="heading-link"><i class="fas fa-link"></i></a>2.container 容器</h3>
      <ul>
<li>可以理解成：“一个运行中的 <strong>docker image</strong>” </li>
<li>实质是复制 <strong>image</strong> 并在 <strong>image</strong> 最上层加上一层 <strong>read write</strong> 的层（称之为 <strong>container layer</strong>，容器层）</li>
<li>基于同一个 <strong>image</strong> 可以创建多个 <strong>container</strong></li>
</ul>

        <h3 id="3-docker-image-的获取">
          <a href="#3-docker-image-的获取" class="heading-link"><i class="fas fa-link"></i></a>3.docker image 的获取</h3>
      <ul>
<li>自己制作</li>
<li>从 <strong>registry</strong> 拉取（比如 <strong>docker hub</strong>）</li>
</ul>

        <h2 id="3、容器的基本操作">
          <a href="#3、容器的基本操作" class="heading-link"><i class="fas fa-link"></i></a>3、容器的基本操作</h2>
      
        <h3 id="1-创建一个容器">
          <a href="#1-创建一个容器" class="heading-link"><i class="fas fa-link"></i></a>1.创建一个容器</h3>
      <p>我们可以通过 <code>docker container run [image_REPOSITORY]</code> 来创建一个容器</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/9.png" alt="图片加载失败"></p>
<p>这里我们可以看到已经成功运行了，我们可以重新打开一个窗口查看一下正在运行的 <strong>container</strong>。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/10.png" alt="图片加载失败"></p>

        <h3 id="2-停止容器">
          <a href="#2-停止容器" class="heading-link"><i class="fas fa-link"></i></a>2.停止容器</h3>
      <p>我们可以通过 <code>docker container stop [IDs or NAMES]</code> 或者 <code>ctrl + c</code> 来停止一个容器</p>
<p><strong>注意：</strong>在 <strong>windows</strong> 中使用 <code>ctrl + c</code>并不能停止容器，实际上还是在后台运行的</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/11.png" alt="图片加载失败"></p>

        <h3 id="3-重新启动停止的容器">
          <a href="#3-重新启动停止的容器" class="heading-link"><i class="fas fa-link"></i></a>3.重新启动停止的容器</h3>
      <p>我们可以通过 <code>docker container start [IDs or NAMES]</code> 来重新启动容器 </p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/15.png" alt="图片加载失败"></p>

        <h3 id="4-删除容器">
          <a href="#4-删除容器" class="heading-link"><i class="fas fa-link"></i></a>4.删除容器</h3>
      <p>我们可以通过 <code>docker container rm [IDs or NAMES]</code> 来删除一个容器</p>
<p>首先，我们查看所有容器：</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/12.png" alt="图片加载失败"></p>
<p>我们可以看到，这里有一个已经停止了的容器，接下来我们删除掉这个容器，再查看一遍</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/13.png" alt="图片加载失败"></p>
<p>通过上图我们可以看到容器已经被删除了。</p>

        <h2 id="4、容器的两种模式（attached、detached）">
          <a href="#4、容器的两种模式（attached、detached）" class="heading-link"><i class="fas fa-link"></i></a>4、容器的两种模式（attached、detached）</h2>
      
        <h3 id="1-attached">
          <a href="#1-attached" class="heading-link"><i class="fas fa-link"></i></a>1.attached</h3>
      <p>这里我们使用 <code>docker container run -p 80:80 nginx</code> 来创建一个容器，<code>-p 80:80</code> 的意思是将容器的内部端口映射到外部端口上。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/19.png" alt="图片加载失败"></p>
<p>我们可以看到已经启动成功了。</p>
<p>接下来，我们在浏览器访问一下虚拟机的 <strong>80</strong> 端口</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/20.png" alt="图片加载失败"> </p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/21.png" alt="图片加载失败"></p>
<p>可以看到，可以成功访问，并且已经打印了相关日志 </p>
<p><font color="red">其实，attached 模式就是，我们的命令会与容器共享。就像我们在 linux 或者 mac 的系统上创建一个 docker 容器后，会显式的显示在窗口中，当我们执行 <code>ctrl + c</code> 后，容器也会停止，这就是 attached 模式</font></p>

        <h3 id="2-detached">
          <a href="#2-detached" class="heading-link"><i class="fas fa-link"></i></a>2.detached</h3>
      <p>这里我们使用 <code>docker container run -d -p 80:80 nginx</code> 来创建一个容器。其中 <code>-d</code> 是指使用 <strong>detached</strong> 模式启动。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/22.png" alt="图片加载失败"></p>
<p>这里我们可以看到，我们只能看到容器的 <strong>id</strong>，并不能看到相关一些信息，也可以看到容器已经成功自动了。</p>
<p>接下来，我们在浏览器访问一下虚拟机的 <strong>80</strong> 端口，就可以看到相关的日志信息并没有打印。</p>
<p>如果，我现在想 <strong>attach</strong> 到容器中该怎么做呢？</p>
<p>我们可以执行 <strong>docker container attach [id or names]**，来 **attach</strong> 到我们的容器。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/23.png" alt="图片加载失败"></p>
<p>通过上图我们可以看到已经成功 <strong>attach</strong> 到我们的容器中了</p>
<p>如果我们不想 <strong>attach</strong> 到我们的容器中，并且还想看日志怎么办呢？</p>
<p>这时，我们可以执行 <code>docker container logs -f [ids or NAMES]</code> 来查看日志。**-f** 是动态的跟踪我们的日志</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/24.png" alt="图片加载失败"></p>

        <h2 id="5、容器的交互模式">
          <a href="#5、容器的交互模式" class="heading-link"><i class="fas fa-link"></i></a>5、容器的交互模式</h2>
      <ol>
<li><p>我们创建一个 <strong>ubuntu</strong> 容器</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> -it 是指交互式的模式</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> sh 执行的命令，就是进入到交互式的 ubuntu 的命令行</span></span><br><span class="line">docker container run -it ubuntu sh</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/25.png" alt="图片加载失败"></p>
<p>这里我们可以看到已经进入到了 <strong>ubuntu</strong> 的命令行了。</p>
<p>当我们执行 <strong>exit</strong> 退出后，在查看容器运行情况，可以看到 <strong>ubuntu</strong> 这个容器已经退出了。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/26.png" alt="图片加载失败"></p>
</li>
<li><p>交互式的进入到已经启动的容器中</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> <span class="built_in">exec</span> 执行</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> -it 交互模式</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> sh 命令行</span></span><br><span class="line">docker container exec -it 79 sh</span><br></pre></td></tr></table></div></figure>

<p>这里可以看到我们已经进来了。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/27.png" alt="图片加载失败"></p>
<p>这个时候我们再次执行 <strong>exit</strong>，并查看容器的启动情况。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/28.png" alt="图片加载失败"></p>
<p>这是因为，我们只是退出了交互式的shell，并不影响这个容器。<font color="red">因为我们交互式的创建一个容器和交互式的进入某个容器是不一样的</font></p>
</li>
</ol>

        <h2 id="6、容器和虚拟机的区别（Container-vs-VM）">
          <a href="#6、容器和虚拟机的区别（Container-vs-VM）" class="heading-link"><i class="fas fa-link"></i></a>6、容器和虚拟机的区别（Container vs VM）</h2>
      <p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/29.png" alt="图片加载失败"></p>
<p>虚拟机是在 <strong>hypervisor</strong> 虚拟化层上创建一整个操作系统，而容器是在 <strong>Container Engine</strong> 容器引擎上的程序，就是一个进程。</p>
<p><strong>容器不是Mini虚拟机：</strong></p>
<ul>
<li>容器其实是进程</li>
<li>容器中的进程被限制了对 <strong>CPU</strong> 内存等资源的访问</li>
<li>当进程结束后，容器就退出了。</li>
</ul>
<p>通过 <code>docker container top [id name]</code> 来查看容器运行了那些进程</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/30.png" alt="图片加载失败"></p>
<p>使用 <code>pstree -halps id</code> 查看进程的依赖关系，使用 <code>yum install psmisc</code> 或者 <code>apt-get install psmisc</code> 安装</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/31.png" alt="图片加载失败"></p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/32.png" alt="图片加载失败"></p>

        <h2 id="7、docker-container-run-容器创建的背后发生了什么？">
          <a href="#7、docker-container-run-容器创建的背后发生了什么？" class="heading-link"><i class="fas fa-link"></i></a>7、docker container run 容器创建的背后发生了什么？</h2>
      <p><code>docker container run -d -p 80:80 --name test nginx</code></p>
<ol>
<li>在本地查找是否有 <strong>nginx</strong> 这个 <strong>image</strong> 镜像，但是发现没有</li>
<li>去远程的 <strong>image registry</strong> 查找 <strong>nginx</strong> 镜像（默认的 <strong>registry</strong> 是 <strong>Docker Hub</strong>）</li>
<li>下载最新版的 <strong>nginx</strong> 镜像（<strong>nginx:latest</strong> 默认）</li>
<li>基于 <strong>nginx</strong> 镜像来创建一个新的容器，并准备运行</li>
<li><strong>docker engine</strong> 分配个这个容器一个虚拟的 <strong>IP</strong> 地址</li>
<li>在宿主机上打开 80 端口并把容器的 80 端口转发到宿主机上</li>
<li>启动容器，运行指定的命令</li>
</ol>

        <h1 id="四、镜像的创建使用管理和发布">
          <a href="#四、镜像的创建使用管理和发布" class="heading-link"><i class="fas fa-link"></i></a>四、镜像的创建使用管理和发布</h1>
      
        <h2 id="1、镜像的获取">
          <a href="#1、镜像的获取" class="heading-link"><i class="fas fa-link"></i></a>1、镜像的获取</h2>
      <ul>
<li><code>pull from registry(online)</code> 从 <strong>registry</strong> 拉取<ul>
<li><strong>public</strong> 公有</li>
<li><strong>private</strong> 私有</li>
</ul>
</li>
<li><code>build from Dockerfile(online)</code> 从 <strong>Dockerfile</strong> 构建</li>
<li><code>load from file(offline)</code> 文件导入（离线）</li>
</ul>
<p><span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://hub.docker.com/">Dockerhub 官网</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span>、<a href="recovery.quay.io">Red Hat quay</a></p>

        <h2 id="2、镜像的获取">
          <a href="#2、镜像的获取" class="heading-link"><i class="fas fa-link"></i></a>2、镜像的获取</h2>
      
        <h3 id="1-在-dockerhub-或-quay-io-获取">
          <a href="#1-在-dockerhub-或-quay-io-获取" class="heading-link"><i class="fas fa-link"></i></a>1.在 dockerhub 或 quay.io 获取</h3>
      <ol>
<li><p>我们先看到一下 <strong>image</strong> 都有哪些命令</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/33.png" alt="图片加载失败"></p>
</li>
<li><p><strong>pull</strong> 拉取镜像</p>
<ul>
<li><p>在 <strong>Docker hub</strong> 找到要拉取的镜像，执行命令拉取即可。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/34.png" alt="图片加载失败"></p>
<p>这里我们可以看到要执行的命令是：<code>docker pull nginx</code>，这是早期版本的命令，建议使用：<code>docker image pull nginx</code></p>
</li>
<li><p>我们还可以拉取别的版本的</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/35.png" alt="图片加载失败"></p>
<p>这里我们使用：<code>docker image pull nginx:1.20.1</code> 就可以拉取了。</p>
</li>
</ul>
</li>
<li><p>查看某个镜像的详细信息</p>
<p>使用 <code>docker image inspect imageID</code> 即可</p>
</li>
<li><p>删除</p>
<p>使用 <code>docker image rm imageID</code> 即可。</p>
<p><font color="red">需要注意的是，如果镜像有某个容器在使用的话是无法删除的。我必须删除掉使用的容器再能删除</font></p>
</li>
</ol>

        <h3 id="2-导入导出方式">
          <a href="#2-导入导出方式" class="heading-link"><i class="fas fa-link"></i></a>2.导入导出方式</h3>
      <ol>
<li><p>导出</p>
<p>我们可以再别的电脑或者环境中保存一个镜像的文件。</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> nginx:1.20.1 要保存的镜像以及版本，如果不添加版本默认latest版本</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> -o 是指 output 输出</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> nginx.image 保存的文件名字</span></span><br><span class="line">docker image save nginx:1.20.1 -o nginx</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/36.png" alt="图片加载失败"></p>
</li>
<li><p>导入</p>
<p>我们先把 1.20.1 版本的删除掉，在进行导入查看</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/37.png" alt="图片加载失败"></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> -i 是指 input 输入</span></span><br><span class="line">docker image load -i nginx</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/38.png" alt="图片加载失败"></p>
</li>
</ol>

        <h3 id="3-Dockerfile-方式">
          <a href="#3-Dockerfile-方式" class="heading-link"><i class="fas fa-link"></i></a>3.Dockerfile 方式</h3>
      
        <h4 id="1）什么是-Dockerfile">
          <a href="#1）什么是-Dockerfile" class="heading-link"><i class="fas fa-link"></i></a>1）什么是 Dockerfile?</h4>
      <ul>
<li>是用于构建 <strong>docker</strong> 镜像的文件</li>
<li>包含了构建镜像所需的指令</li>
<li>有特定的语法规则</li>
</ul>

        <h4 id="2）举例：执行一个-Python-程序">
          <a href="#2）举例：执行一个-Python-程序" class="heading-link"><i class="fas fa-link"></i></a>2）举例：执行一个 Python 程序</h4>
      <p>假如我们要在一台 <strong>ubuntu 21.04</strong> 上运行下面这个 <strong>hello.py</strong> 的 <strong>Python</strong> 程序</p>
<p><strong>hello.py</strong> 的文件内容：</p>
<figure class="highlight python"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">print(<span class="string">&quot;hello docker&quot;</span>)</span><br></pre></td></tr></table></div></figure>

<p>第一步，准备 <strong>Python</strong> 的环境</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apt-get update &amp;&amp; /</span><br><span class="line">DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y python3.9 python3-pip python3.9-dev</span><br></pre></td></tr></table></div></figure>

<p>第二步，运行 <strong>hello.py</strong></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> python3 hello.py</span></span><br><span class="line">输入：hello docker</span><br></pre></td></tr></table></div></figure>


        <h4 id="3）一个-Dockerfile-的基本结构">
          <a href="#3）一个-Dockerfile-的基本结构" class="heading-link"><i class="fas fa-link"></i></a>3）一个 Dockerfile 的基本结构</h4>
      <ol>
<li><p><strong>Dockerfile</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 引入 ubuntu:21.04 镜像</span></span><br><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="comment"># 执行命令安装 python 的环境</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get update &amp;&amp; \</span></span><br><span class="line"><span class="bash">    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y python3.9 python3-pip python3.9-dev</span></span><br><span class="line"><span class="comment"># 将本地的 hello.py 文件添加到 / 根目录下</span></span><br><span class="line"><span class="keyword">ADD</span><span class="bash"> hello.py /</span></span><br><span class="line"><span class="comment"># 执行命令</span></span><br><span class="line"><span class="keyword">CMD</span><span class="bash"> [<span class="string">&quot;python3&quot;</span>,<span class="string">&quot;/hello.py&quot;</span>]</span></span><br></pre></td></tr></table></div></figure>

<p>详细可见 <span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://docs.docker.com/engine/reference/builder/">Dockerfile 官方文档</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/39.png" alt="图片加载失败"></p>
</li>
<li><p><strong>通过 Dockerfile 构建镜像</strong></p>
<p>由于我的 <strong>centos</strong> 是一台虚拟机，并且没有做桥接，所以在 <strong>centos</strong> 中拉下来的镜像网络不通无法进行 <strong>apt-get update</strong>，所以在我的另一台 <strong>kali</strong> 系统的电脑上进行的测试，<font color="red">并且后续所有测试都在 <strong>kali</strong> 上进行</font></p>
<ul>
<li><p>首先我们先将 <strong>hello.py</strong> 和 <strong>Dockerfile</strong> 准备好</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/40.png" alt="图片加载失败"></p>
</li>
<li><p>通过 <code>docker image build</code> 进行构建</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> -f DockerFile 的名字</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> -t 构建后镜像名称</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> . 当前目录下</span></span><br><span class="line">docker image build -t hello .</span><br><span class="line"></span><br><span class="line">docker image build -f DockfileName -t Tag .</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/41.png" alt="图片加载失败"></p>
</li>
<li><p>可以看到镜像已经构建成功了</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/42.png" alt="图片加载失败"></p>
</li>
<li><p>使用构建的镜像创建容器</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/43.png" alt="图片加载失败"></p>
<p>可以看到，<strong>hello docker</strong> 已经打印出来了，并且容器已经退出了。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/44.png" alt="图片加载失败"></p>
</li>
<li><p>为甚么直接退出了？</p>
<p>因为 <strong>Dockerfile</strong> 中的 <code>CMD [&quot;python3&quot;,&quot;/hello.py&quot;]</code> 执行完之后就停了，这个进程停了，容器自然就停了</p>
</li>
</ul>
</li>
</ol>

        <h3 id="4、通过-container-容器生成一个镜像">
          <a href="#4、通过-container-容器生成一个镜像" class="heading-link"><i class="fas fa-link"></i></a>4、通过 container 容器生成一个镜像</h3>
      <p>我们可以使用 <code>docker container commit contaienrId ImageName</code> 命令，根据 <strong>container</strong> 生成一个镜像</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/51.png" alt="图片加载失败"></p>

        <h2 id="3、镜像的分享">
          <a href="#3、镜像的分享" class="heading-link"><i class="fas fa-link"></i></a>3、镜像的分享</h2>
      
        <h3 id="1-可以通过导出的方式进行分享">
          <a href="#1-可以通过导出的方式进行分享" class="heading-link"><i class="fas fa-link"></i></a>1.可以通过导出的方式进行分享</h3>
      <figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> nginx:1.20.1 要保存的镜像以及版本，如果不添加版本默认latest版本</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> -o 是指 output 输出</span></span><br><span class="line"><span class="meta">#</span><span class="bash"> nginx.image 保存的文件名字</span></span><br><span class="line">docker image save nginx:1.20.1 -o nginx</span><br></pre></td></tr></table></div></figure>


        <h3 id="2-push-到-dockerhub-中进行分享">
          <a href="#2-push-到-dockerhub-中进行分享" class="heading-link"><i class="fas fa-link"></i></a>2.push 到 dockerhub 中进行分享</h3>
      <ol>
<li><p>首先要在 <strong>dockerhub</strong> 注册一个账号，我们的镜像格式都是 <strong>id/imageName</strong></p>
</li>
<li><p>在 <strong>push</strong> 之前我们的镜像 <strong>tag</strong> 要符合我们 <strong>dockerhub</strong> 的规范</p>
<ul>
<li><p>我们可以通过重新构建来修改镜像的 <strong>tag</strong></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker image build -t DockerhubID/imageName:version .</span><br></pre></td></tr></table></div></figure>
</li>
<li><p>我们还可以通过已经存在的镜像复制一个新的镜像</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker image tag hello sunyubk/hello:1.0</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/45.png" alt="图片加载失败"></p>
</li>
</ul>
<p><font color="red">注意：通过以上两种方式生成的新的镜像的 id 是相同的，无法根据 id 进行删除，所以我们可以通过 image:tag 删除</font></p>
</li>
<li><p>push</p>
<ul>
<li><p>在 <strong>push **之前我们还需要登录到 **dockerhub</strong>，<code>docker login</code></p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/46.png" alt="图片加载失败"></p>
<p>这里可以看到我们已经登录成功了</p>
</li>
<li><p>我们可以通过 <code>docker image push sunyubk/hello:1.0</code> 进行 **push **了。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/47.png" alt="图片加载失败"></p>
</li>
<li><p><strong>push ** 后我们就可以在我们的 **dockerhub</strong> 中看到我们 <strong>push</strong> 的镜像了</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/48.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
<li><p>拉取测试</p>
<ul>
<li><p>我们先将本地的 <strong>sunyubk/hello:1.0</strong> 这个镜像删除掉在进行拉取</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/49.png" alt="图片加载失败"></p>
</li>
<li><p>我们将镜像拉取下来，并运行测试</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/50.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
</ol>

        <h1 id="五、Dockerfile">
          <a href="#五、Dockerfile" class="heading-link"><i class="fas fa-link"></i></a>五、Dockerfile</h1>
      
        <h2 id="1、基础镜像的选择">
          <a href="#1、基础镜像的选择" class="heading-link"><i class="fas fa-link"></i></a>1、基础镜像的选择</h2>
      <ul>
<li>官方镜像优于非官方镜像，如果没有官方镜像，则尽量选择 <strong>Dockerfile</strong> 开源的</li>
<li>固定版本 <strong>tag</strong> 而不是每次都是用 <strong>latest</strong></li>
<li>尽量选择体积小的镜像</li>
</ul>

        <h2 id="2、通过-RUN-执行指令">
          <a href="#2、通过-RUN-执行指令" class="heading-link"><i class="fas fa-link"></i></a>2、通过 RUN 执行指令</h2>
      <p><code>RUN</code> 主要用于在 <strong>image</strong> 里执行指令，比如安装软件，下载文件等。</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> apt-get update</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> apt-get install wget</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> wget wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> tar -zxvf ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> mv ipinfo_2.0.1_linxu_amd64.tar.gz /usr/bin/ipinfo</span></span><br><span class="line"><span class="meta">$</span><span class="bash"> rm -rf ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br></pre></td></tr></table></div></figure>

<p><strong>Dockerfile</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get update</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get install wget</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> tar -zxvf ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> ipinfo_2.0.1_linxu_amd64.tar.gz /usr/bin/ipinfo</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> rm -rf ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br></pre></td></tr></table></div></figure>

<p><strong>镜像的大小和分层</strong></p>
<p>每个 <code>RUN</code> 命令的执行都会产生一层 <strong>image layer</strong> ，这样会导致镜像比较臃肿。</p>
<p><strong>改进版 Dockerfile</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get update $$ \</span></span><br><span class="line"><span class="bash">    apt-get install wget $$ \</span></span><br><span class="line"><span class="bash">    wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    tar -zxvf ipinfo_2.0.1_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    mv ipinfo_2.0.1_linxu_amd64.tar.gz /usr/bin/ipinfo $$ \</span></span><br><span class="line"><span class="bash">    rm -rf ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br></pre></td></tr></table></div></figure>

<p>这样编写的 <strong>Dockerfile</strong> 只会通过一个 <code>RUN</code> 命令执行，只会产生一层。</p>

        <h2 id="3、文件复制和目录操作">
          <a href="#3、文件复制和目录操作" class="heading-link"><i class="fas fa-link"></i></a>3、文件复制和目录操作</h2>
      <ol>
<li><p>文件复制</p>
<p>往镜像中复制文件有两种方式，分别是 <code>copy</code> 和 <code>add</code>。</p>
<p><strong>复制普通文件</strong></p>
<p> <code>copy</code> 和 <code>add</code> 都可以把 <strong>local</strong> 的一个文件复制到镜像中，如果目标目录不存在，则会自动创建</p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> python:<span class="number">3.9</span>.<span class="number">5</span>-alpine3.<span class="number">13</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> hello.py /app/hello.py</span></span><br></pre></td></tr></table></div></figure>

<p><strong>复制压缩文件</strong></p>
<p><code>add</code> 比 <code>copy</code> 高级一点的地方就是，如果复制一个 <strong>gzip</strong> 等压缩文件时，<code>add</code> 会帮助我们去自动解压缩文件。</p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> python:<span class="number">3.9</span>.<span class="number">5</span>-alpine3.<span class="number">13</span></span><br><span class="line"><span class="keyword">ADD</span><span class="bash"> hello.tar.gz /app/</span></span><br></pre></td></tr></table></div></figure>

<p><strong>如何选择</strong></p>
<p>在 <code>copy</code> 和 <code>add</code> 指令的选择的时候，可以遵循这样的原则，所有文件复制均使用 <code>copy</code>，仅在需要自动解压缩的场合使用 <code>add</code>。</p>
</li>
<li><p>目录操作</p>
<p><strong>目录切换</strong></p>
<p><code>WORKDIR</code> 切换目录，如果要切换的目录不存在，则创建目录</p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> python:<span class="number">3.9</span>.<span class="number">5</span>-alpine3.<span class="number">13</span></span><br><span class="line"><span class="keyword">WORKDIR</span><span class="bash"> /app</span></span><br><span class="line"><span class="keyword">COPY</span><span class="bash"> hello.py /hello.py</span></span><br></pre></td></tr></table></div></figure>

</li>
</ol>

        <h2 id="4、构建参数和环境变量（ARG-vs-ENV）">
          <a href="#4、构建参数和环境变量（ARG-vs-ENV）" class="heading-link"><i class="fas fa-link"></i></a>4、构建参数和环境变量（ARG vs ENV）</h2>
      <p><code>ARG</code> 和 <code>ENV</code> 是经常被混淆的两个 <strong>Dockerfile</strong> 的语法，都可以用来设置一个 <strong>变量</strong>。但实际上两者会有很多的不同。</p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get update $$ \</span></span><br><span class="line"><span class="bash">    apt-get install wget $$ \</span></span><br><span class="line"><span class="bash">    wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    tar -zxvf ipinfo_2.0.1_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    mv ipinfo_2.0.1_linxu_amd64.tar.gz /usr/bin/ipinfo $$ \</span></span><br><span class="line"><span class="bash">    rm -rf ipinfo_2.0.1_linxu_amd64.tar.gz</span></span><br></pre></td></tr></table></div></figure>

<p><strong>ENV</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">ENV</span> VERSION=<span class="number">2.0</span>.<span class="number">1</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get update $$ \</span></span><br><span class="line"><span class="bash">    apt-get install wget $$ \</span></span><br><span class="line"><span class="bash">    wget https://github.com/ipinfo/cli/releases/download/ipinfo-<span class="variable">$&#123;VERSION&#125;</span>/ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    tar -zxvf ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    mv ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz /usr/bin/ipinfo $$ \</span></span><br><span class="line"><span class="bash">    rm -rf ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz</span></span><br></pre></td></tr></table></div></figure>

<p><strong>ARG</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">ARG</span> VERSION=<span class="number">2.0</span>.<span class="number">1</span></span><br><span class="line"><span class="keyword">RUN</span><span class="bash"> apt-get update $$ \</span></span><br><span class="line"><span class="bash">    apt-get install wget $$ \</span></span><br><span class="line"><span class="bash">    wget https://github.com/ipinfo/cli/releases/download/ipinfo-<span class="variable">$&#123;VERSION&#125;</span>/ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    tar -zxvf ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz $$ \</span></span><br><span class="line"><span class="bash">    mv ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz /usr/bin/ipinfo $$ \</span></span><br><span class="line"><span class="bash">    rm -rf ipinfo_<span class="variable">$&#123;VERSION&#125;</span>_linxu_amd64.tar.gz</span></span><br></pre></td></tr></table></div></figure>

<p><strong>区别</strong></p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/52.png" alt="图片加载失败"></p>
<ul>
<li><strong>ARG</strong> 使用的范围是 <strong>Dockerfile</strong> 构建的阶段，构建后则无法使用了，因为这个变量不会保存在镜像中。</li>
<li><strong>ENV</strong> 使用的范围不仅是在 <strong>Dockerfile</strong> 构建的阶段，而且这个变量会作为 <strong>环境变量</strong> 保存在镜像中，当我们使用这个镜像去创建容器的时候也可以使用这个变量</li>
</ul>
<p><font color="red">ARG 还可一在构建的时候动态的修改值， ENV 则不可以</font></p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/53.png" alt="图片加载失败"></p>
<p>例如：</p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker image build -f ./Dockerfile-<span class="keyword">arg</span> -t ipinfo-<span class="keyword">arg</span>-<span class="number">2.0</span>.<span class="number">0</span> --build-<span class="keyword">arg</span> VERSION=<span class="number">2.0</span>.<span class="number">0</span> .</span><br></pre></td></tr></table></div></figure>


        <h2 id="5、CMD-容器启动命令">
          <a href="#5、CMD-容器启动命令" class="heading-link"><i class="fas fa-link"></i></a>5、CMD 容器启动命令</h2>
      <p><strong>CMD</strong> 可以用来设置容器启动时默认会执行的命令。</p>
<ul>
<li>容器启动时默认执行的命令</li>
<li>如果 <strong>docker container run</strong> 启动容器是指定了其它命令，则 <strong>CMD</strong> 命令会被忽略</li>
<li>如果定义了多个 <strong>CMD</strong> ，只有最后一个会被执行</li>
</ul>

        <h2 id="6、ENTRYPOINT-容器启动命令">
          <a href="#6、ENTRYPOINT-容器启动命令" class="heading-link"><i class="fas fa-link"></i></a>6、ENTRYPOINT 容器启动命令</h2>
      <p><strong>ENTRYPOINT</strong> 也可以设置容器启动时要执行的命令，但是和 <strong>CMD</strong> 是有区别的。</p>
<ul>
<li><strong>CMD</strong> 设置的命令，可以再 <code>docker container run</code> 时传入其他命令，覆盖掉 <strong>CMD</strong> 命令，但是 <strong>ENTRYPOINT</strong> 所设置的命令是一定会被执行的。</li>
<li><strong>ENTRYPOINT</strong> 和 <strong>CMD</strong> 可以联合使用，<strong>ENTRYPOINT</strong> 设置执行的命令，<strong>CMD</strong> 传递参数</li>
</ul>
<ol>
<li><p>准备三个 <strong>Dockerfile</strong>，并构建成相应的镜像</p>
<p><strong>Dockerfile-cmd</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">CMD</span><span class="bash"> [<span class="string">&quot;echo&quot;</span>,<span class="string">&quot;hello docker&quot;</span>]</span></span><br></pre></td></tr></table></div></figure>

<p><strong>Dockerfile-entrypoint</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="bash"> [<span class="string">&quot;echo&quot;</span>,<span class="string">&quot;hello docker&quot;</span>]</span></span><br></pre></td></tr></table></div></figure>

<p><strong>Dockerfile-both</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">ENTRYPOINT</span><span class="bash"> [<span class="string">&quot;echo&quot;</span>]</span></span><br><span class="line"><span class="keyword">CMD</span><span class="bash"> []</span></span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/54.png" alt="图片加载失败"></p>
</li>
<li><p>根据镜像创建容器</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash"> -rm 运行后删除容器</span></span><br><span class="line">docker container run --rm -it imagename</span><br></pre></td></tr></table></div></figure>

<p><strong>demo-cmd</strong></p>
<p>在下图中可以看到，如果在创建容器的时候指定命令，则 <strong>CMD</strong> 中的命令不会运行</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/55.png" alt="图片加载失败"></p>
<p><strong>demo-entrypoint</strong></p>
<p>在下图中可以看到，如果在创建容器的时候指定指令，指令会作为参数传递进去，原本 <strong>Dockerfile-entrypoint</strong> 中的 <strong>ENTRYPOINT</strong> 肯定会执行。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/56.png" alt="图片加载失败"></p>
<p><strong>demo-bot</strong></p>
<p>在下图 中可以看到：</p>
<p>第一遍命令什么都没有打印，这是因为 <strong>Dockerfile-both</strong> 中的 <strong>ENTRYPOINT</strong> 执行了 <code>echo</code> ,但是并没有设置要打印的值。</p>
<p>第二遍命令打印了创建容器是指定的命令，这是因为将指定的命令作为参数传递进去了。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/56.png" alt="图片加载失败"></p>
</li>
</ol>

        <h2 id="7、Shell-格式和-Exec-格式">
          <a href="#7、Shell-格式和-Exec-格式" class="heading-link"><i class="fas fa-link"></i></a>7、Shell 格式和 Exec 格式</h2>
      <p><strong>CMD</strong> 和 <strong>ENTRYPOINT</strong> 都支持 <strong>Shell</strong> 格式和 <strong>Exec</strong> 格式</p>
<p><strong>Shell</strong> 格式</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">CMD echo &quot;hello docker&quot;</span><br><span class="line">ENTRYPOINT echo &quot;hello docker&quot;</span><br></pre></td></tr></table></div></figure>

<p><strong>Exec</strong> 格式</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">CMD [&quot;echo&quot;,&quot;hello docker&quot;]</span><br><span class="line">ENTRYPOINT [&quot;echo&quot;,&quot;hello docker&quot;]</span><br></pre></td></tr></table></div></figure>

<p><strong>注意 Shell 脚本问题</strong></p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">ENV</span> NAME=docker</span><br><span class="line"><span class="keyword">CMD</span><span class="bash"> <span class="built_in">echo</span> <span class="string">&quot;hello <span class="variable">$NAME</span>&quot;</span></span></span><br></pre></td></tr></table></div></figure>

<p>假如我们要把上面的 <strong>CMD</strong> 改成 <strong>Exec</strong> 格式，下面这样改是不行的。</p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">ENV</span> NAME=docker</span><br><span class="line"><span class="keyword">CMD</span><span class="bash"> CMD [<span class="string">&quot;echo&quot;</span>,<span class="string">&quot;hello <span class="variable">$NAME</span>&quot;</span>]</span></span><br></pre></td></tr></table></div></figure>

<p>它会打印出 <code>hello $NAME</code>，而不是 <code>hello docker</code>。这里就需要以 <strong>shell</strong> 脚本的方式去执行</p>
<figure class="highlight dockerfile"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">FROM</span> ubuntu:<span class="number">21.04</span></span><br><span class="line"><span class="keyword">ENV</span> NAME=docker</span><br><span class="line"><span class="keyword">CMD</span><span class="bash"> CMD [<span class="string">&quot;sh&quot;</span>,<span class="string">&quot;-c&quot;</span>,<span class="string">&quot;echo hello <span class="variable">$N</span>&quot;</span>]</span></span><br></pre></td></tr></table></div></figure>


        <h1 id="六、数据持久化">
          <a href="#六、数据持久化" class="heading-link"><i class="fas fa-link"></i></a>六、数据持久化</h1>
      <p>为什么需要数据持久化：因为当我们将容器（<strong>cotainer</strong>）删除之后，那么我们容器中的数据也会被删除。（数据不随着 Container 的结束而结束）</p>

        <h2 id="1、Data-volume">
          <a href="#1、Data-volume" class="heading-link"><i class="fas fa-link"></i></a>1、Data volume</h2>
      <p><strong>Data volume</strong> 是 <strong>Docker</strong> 一个<font color="red">卷</font> 的概念，就是 <strong>Docker</strong> 管理宿主机文件系统的一部分，默认位于 <code>/var/lib/docker/volumes</code> 目录中。</p>
<p>这里我们使用 <strong>mysql</strong> 的镜像来演示：</p>
<ol>
<li><p>首先我们先准备 <strong>mysql:5.7</strong> 的镜像</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/58.png" alt="图片加载失败"></p>
</li>
<li><p>创建容器</p>
<p>关于 <strong>MySQL</strong> 镜像的使用可以参考：<span class="exturl"><a class="exturl__link" target="_blank" rel="noopener" href="https://hub.docker.com/_/mysql">dockerhub中mysql</a><span class="exturl__icon"><i class="fas fa-external-link-alt"></i></span></span></p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">-e 设置mysql root用户的密码</span><br><span class="line">-v 使用volume持久化数据 volume 名称：容器内目录，如果不指定则会默认生成一个随机的文件</span><br><span class="line">docker container run -d --name mysql_5.7 -e MYSQL_ROOT_PASSWORD=root -v mysql_data:/var/lib/mysql mysql:5.7</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/59.png" alt="图片加载失败"></p>
</li>
<li><p>进入容器进行测试</p>
<ul>
<li><p>我们交互式的进入到容器的中，并连接进入mysql，并且查看数据库，可以看到数据库是初始化的状态。</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/60.png" alt="图片加载失败"></p>
</li>
<li><p>我们创建一个数据库，并退出到容器</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/61.png" alt="图片加载失败"></p>
</li>
<li><p>我们进入容器的 <code>/var/lib/mysql</code> 目录下，也可以看到我们创建的数据库在这里生成了文件夹</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/62.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
<li><p>退出容器，查看我们本地 <strong>volume</strong>文件</p>
<ul>
<li><p>查看 <strong>volume</strong> 列表</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume ls</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/63.png" alt="图片加载失败"></p>
</li>
<li><p>查看对应的文件信息</p>
<figure class="highlight shell"><div class="table-container"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker volume inspect mysql_data</span><br></pre></td></tr></table></div></figure>

<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/64.png" alt="图片加载失败"></p>
<p>这里看到的目录就是与容器中 <strong>mysql</strong> 目录绑定的目录</p>
</li>
<li><p>我们查看目录下的文件</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/65.png" alt="图片加载失败"></p>
<p>可以看到，<code>test</code> 已经在目录下了。</p>
</li>
</ul>
<p><strong>测试：</strong></p>
<ol>
<li><p>我们在容器中创建文件/文件夹，会不会同步到对应的volume中？</p>
<ul>
<li><p>我们先进入容器中</p>
</li>
<li><p>在持久化的目录中新建一个文件夹</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/66.png" alt="图片加载失败"></p>
</li>
<li><p>我们在 volume 中产看</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/67.png" alt="图片加载失败"></p>
<p>可以看到，我们创建的文件夹在 volume 中已经出现了</p>
</li>
</ul>
</li>
<li><p>如果我们将 volume 中的文件删除，容器中会同步么？</p>
<ul>
<li><p>我们删除 volume 目录中创建的文件夹</p>
</li>
<li><p>我们回到容器中的目录查看</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/67.png" alt="图片加载失败"></p>
<p>可以看到，文件夹也不见了</p>
</li>
</ul>
</li>
</ol>
<p>通过这个测试，我们可以看出，<strong>volume</strong> 帮我们做了一个类似软连接的功能。在容器里面的改动，可以再宿主机中感知，而在宿主机里面的改动，在容器中也可以感知。</p>
<p><strong>注意：</strong></p>
<ul>
<li>如果 <strong>volume</strong> 是空的，而 <strong>container</strong> 中有内容，那么 <strong>docker</strong> 会将 <strong>container</strong> 中的内容拷贝到 <strong>volume</strong> 中</li>
<li>如果 <strong>volume</strong> 中已经有内容，则会将 <strong>container</strong> 中的目录覆盖掉。</li>
</ul>
</li>
</ol>

        <h1 id="命令行小技巧">
          <a href="#命令行小技巧" class="heading-link"><i class="fas fa-link"></i></a>命令行小技巧</h1>
      
        <h2 id="1、批量操作">
          <a href="#1、批量操作" class="heading-link"><i class="fas fa-link"></i></a>1、批量操作</h2>
      <ol>
<li><p>我们可以通过 <code>docker container ls -aq</code> 获取到所有 <strong>container</strong> 的id</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/14.png" alt="图片加载失败"></p>
</li>
<li><p>我们可以通过参数的方式将这些 <strong>id</strong>，进行一个传递</p>
<ul>
<li><p>批量启动</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/16.png" alt="图片加载失败"></p>
</li>
<li><p>批量停止</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/17.png" alt="图片加载失败"></p>
</li>
<li><p>批量删除</p>
<p><img src="/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/18.png" alt="图片加载失败"></p>
</li>
</ul>
</li>
</ol>

        <h2 id="2、系统清理">
          <a href="#2、系统清理" class="heading-link"><i class="fas fa-link"></i></a>2、系统清理</h2>
      <ol>
<li>我们可以使用 <code>docker container prune -f</code>，来清理掉已经停止的容器</li>
<li>我们可以使用 <code>docker image prune -a</code>，来清理掉没有使用的镜像y</li>
</ol>
</div><footer class="post-footer"><div class="post-ending ending"><div class="ending__text">------ 本文结束，感谢您的阅读 ------</div></div><div class="post-copyright copyright"><div class="copyright-author"><span class="copyright-author__name">本文作者: </span><span class="copyright-author__value"><a href="http://yoursite.com">孙宇</a></span></div><div class="copyright-link"><span class="copyright-link__name">本文链接: </span><span class="copyright-link__value"><a href="http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/">http://yoursite.com/2021/08/26/Docker%E5%AD%A6%E4%B9%A0/</a></span></div><div class="copyright-notice"><span class="copyright-notice__name">版权声明: </span><span class="copyright-notice__value">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" rel="external nofollow" target="_blank">BY-NC-SA</a> 许可协议。转载请注明出处！</span></div></div><div class="post-tags"><span class="post-tags-item"><span class="post-tags-item__icon"><i class="fas fa-tag"></i></span><a class="post-tags-item__link" href="http://yoursite.com/tags/Docker/">Docker</a></span></div><nav class="post-paginator paginator"><div class="paginator-next"><a class="paginator-next__link" href="/2021/08/06/Redis%E5%AD%A6%E4%B9%A0/"><span class="paginator-prev__text">Redis学习</span><span class="paginator-next__icon"><i class="fas fa-angle-right"></i></span></a></div></nav></footer></div></div><div class="comments" id="comments"><div id="gitalk-container"></div></div></div><div class="sidebar-wrap" id="sidebar-wrap"><aside class="sidebar" id="sidebar"><div class="sidebar-nav"><span class="sidebar-nav-toc current">文章目录</span><span class="sidebar-nav-ov">站点概览</span></div><section class="sidebar-toc"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%80%E3%80%81%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87"><span class="toc-text">
          一、环境准备</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%8C%E3%80%81%E5%AE%89%E8%A3%85"><span class="toc-text">
          二、安装</span></a></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%B8%89%E3%80%81%E5%AE%B9%E5%99%A8%E7%9A%84%E5%BF%AB%E9%80%9F%E4%B8%8A%E6%89%8B"><span class="toc-text">
          三、容器的快速上手</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81docker-%E7%9A%84%E5%91%BD%E4%BB%A4%E8%A1%8C"><span class="toc-text">
          1、docker 的命令行</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81docker-%E7%9A%84%E9%95%9C%E5%83%8F-VS-%E5%AE%B9%E5%99%A8"><span class="toc-text">
          2、docker 的镜像 VS 容器</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-image-%E9%95%9C%E5%83%8F"><span class="toc-text">
          1.image 镜像</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-container-%E5%AE%B9%E5%99%A8"><span class="toc-text">
          2.container 容器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-docker-image-%E7%9A%84%E8%8E%B7%E5%8F%96"><span class="toc-text">
          3.docker image 的获取</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E5%AE%B9%E5%99%A8%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C"><span class="toc-text">
          3、容器的基本操作</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%AE%B9%E5%99%A8"><span class="toc-text">
          1.创建一个容器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-%E5%81%9C%E6%AD%A2%E5%AE%B9%E5%99%A8"><span class="toc-text">
          2.停止容器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-%E9%87%8D%E6%96%B0%E5%90%AF%E5%8A%A8%E5%81%9C%E6%AD%A2%E7%9A%84%E5%AE%B9%E5%99%A8"><span class="toc-text">
          3.重新启动停止的容器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-%E5%88%A0%E9%99%A4%E5%AE%B9%E5%99%A8"><span class="toc-text">
          4.删除容器</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E5%AE%B9%E5%99%A8%E7%9A%84%E4%B8%A4%E7%A7%8D%E6%A8%A1%E5%BC%8F%EF%BC%88attached%E3%80%81detached%EF%BC%89"><span class="toc-text">
          4、容器的两种模式（attached、detached）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-attached"><span class="toc-text">
          1.attached</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-detached"><span class="toc-text">
          2.detached</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E5%AE%B9%E5%99%A8%E7%9A%84%E4%BA%A4%E4%BA%92%E6%A8%A1%E5%BC%8F"><span class="toc-text">
          5、容器的交互模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81%E5%AE%B9%E5%99%A8%E5%92%8C%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%88Container-vs-VM%EF%BC%89"><span class="toc-text">
          6、容器和虚拟机的区别（Container vs VM）</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81docker-container-run-%E5%AE%B9%E5%99%A8%E5%88%9B%E5%BB%BA%E7%9A%84%E8%83%8C%E5%90%8E%E5%8F%91%E7%94%9F%E4%BA%86%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-text">
          7、docker container run 容器创建的背后发生了什么？</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%9B%9B%E3%80%81%E9%95%9C%E5%83%8F%E7%9A%84%E5%88%9B%E5%BB%BA%E4%BD%BF%E7%94%A8%E7%AE%A1%E7%90%86%E5%92%8C%E5%8F%91%E5%B8%83"><span class="toc-text">
          四、镜像的创建使用管理和发布</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E9%95%9C%E5%83%8F%E7%9A%84%E8%8E%B7%E5%8F%96"><span class="toc-text">
          1、镜像的获取</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E9%95%9C%E5%83%8F%E7%9A%84%E8%8E%B7%E5%8F%96"><span class="toc-text">
          2、镜像的获取</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E5%9C%A8-dockerhub-%E6%88%96-quay-io-%E8%8E%B7%E5%8F%96"><span class="toc-text">
          1.在 dockerhub 或 quay.io 获取</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA%E6%96%B9%E5%BC%8F"><span class="toc-text">
          2.导入导出方式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-Dockerfile-%E6%96%B9%E5%BC%8F"><span class="toc-text">
          3.Dockerfile 方式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%EF%BC%89%E4%BB%80%E4%B9%88%E6%98%AF-Dockerfile"><span class="toc-text">
          1）什么是 Dockerfile?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%EF%BC%89%E4%B8%BE%E4%BE%8B%EF%BC%9A%E6%89%A7%E8%A1%8C%E4%B8%80%E4%B8%AA-Python-%E7%A8%8B%E5%BA%8F"><span class="toc-text">
          2）举例：执行一个 Python 程序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%EF%BC%89%E4%B8%80%E4%B8%AA-Dockerfile-%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%BB%93%E6%9E%84"><span class="toc-text">
          3）一个 Dockerfile 的基本结构</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4%E3%80%81%E9%80%9A%E8%BF%87-container-%E5%AE%B9%E5%99%A8%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AA%E9%95%9C%E5%83%8F"><span class="toc-text">
          4、通过 container 容器生成一个镜像</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E9%95%9C%E5%83%8F%E7%9A%84%E5%88%86%E4%BA%AB"><span class="toc-text">
          3、镜像的分享</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%AF%BC%E5%87%BA%E7%9A%84%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E5%88%86%E4%BA%AB"><span class="toc-text">
          1.可以通过导出的方式进行分享</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-push-%E5%88%B0-dockerhub-%E4%B8%AD%E8%BF%9B%E8%A1%8C%E5%88%86%E4%BA%AB"><span class="toc-text">
          2.push 到 dockerhub 中进行分享</span></a></li></ol></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E4%BA%94%E3%80%81Dockerfile"><span class="toc-text">
          五、Dockerfile</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E5%9F%BA%E7%A1%80%E9%95%9C%E5%83%8F%E7%9A%84%E9%80%89%E6%8B%A9"><span class="toc-text">
          1、基础镜像的选择</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E9%80%9A%E8%BF%87-RUN-%E6%89%A7%E8%A1%8C%E6%8C%87%E4%BB%A4"><span class="toc-text">
          2、通过 RUN 执行指令</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E6%96%87%E4%BB%B6%E5%A4%8D%E5%88%B6%E5%92%8C%E7%9B%AE%E5%BD%95%E6%93%8D%E4%BD%9C"><span class="toc-text">
          3、文件复制和目录操作</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E6%9E%84%E5%BB%BA%E5%8F%82%E6%95%B0%E5%92%8C%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%EF%BC%88ARG-vs-ENV%EF%BC%89"><span class="toc-text">
          4、构建参数和环境变量（ARG vs ENV）</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81CMD-%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E5%91%BD%E4%BB%A4"><span class="toc-text">
          5、CMD 容器启动命令</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6%E3%80%81ENTRYPOINT-%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E5%91%BD%E4%BB%A4"><span class="toc-text">
          6、ENTRYPOINT 容器启动命令</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7%E3%80%81Shell-%E6%A0%BC%E5%BC%8F%E5%92%8C-Exec-%E6%A0%BC%E5%BC%8F"><span class="toc-text">
          7、Shell 格式和 Exec 格式</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%AD%E3%80%81%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96"><span class="toc-text">
          六、数据持久化</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81Data-volume"><span class="toc-text">
          1、Data volume</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%B0%8F%E6%8A%80%E5%B7%A7"><span class="toc-text">
          命令行小技巧</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E6%89%B9%E9%87%8F%E6%93%8D%E4%BD%9C"><span class="toc-text">
          1、批量操作</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E7%B3%BB%E7%BB%9F%E6%B8%85%E7%90%86"><span class="toc-text">
          2、系统清理</span></a></li></ol></li></ol></section><!-- ov = overview--><section class="sidebar-ov hide"><div class="sidebar-ov-author"><div class="sidebar-ov-author__avatar"><img class="sidebar-ov-author__avatar_img" src="/images/img_head.jpg" alt="avatar"></div><p class="sidebar-ov-author__text">悠闲时光</p></div><div class="sidebar-ov-state"><a class="sidebar-ov-state-item sidebar-ov-state-item--posts" href="/archives/"><div class="sidebar-ov-state-item__count">14</div><div class="sidebar-ov-state-item__name">归档</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--categories" href="/categories/"><div class="sidebar-ov-state-item__count">10</div><div class="sidebar-ov-state-item__name">分类</div></a><a class="sidebar-ov-state-item sidebar-ov-state-item--tags" href="/tags/"><div class="sidebar-ov-state-item__count">7</div><div class="sidebar-ov-state-item__name">标签</div></a></div><div class="sidebar-ov-cc"><a href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en" target="_blank" rel="noopener" data-popover="知识共享许可协议" data-popover-pos="up"><img src="/images/cc-by-nc-sa.svg"></a></div></section><div class="sidebar-reading"><div class="sidebar-reading-info"><span class="sidebar-reading-info__text">你已阅读了 </span><span class="sidebar-reading-info__num">0</span></div><div class="sidebar-reading-line"></div></div></aside></div><div class="clearfix"></div></div></main><footer class="footer" id="footer"><div class="footer-inner"><div><span>Copyright © 2021</span><span class="footer__icon"><i class="fas fa-heart"></i></span><span>孙宇</span></div><div><span>由 <a href="http://hexo.io/" title="Hexo" target="_blank" rel="noopener">Hexo</a> 强力驱动</span><span> v5.0.2</span><span class="footer__devider">|</span><span>主题 - <a href="https://github.com/liuyib/hexo-theme-stun/" title="Stun" target="_blank" rel="noopener">Stun</a></span><span> v2.0.0-rc.0</span></div></div></footer><div class="loading-bar" id="loading-bar"><div class="loading-bar__progress"></div></div><div class="back2top" id="back2top"><span class="back2top__icon"><i class="fas fa-rocket"></i></span></div></div><div class="search-mask"></div><div class="search-popup"><span class="search-close"></span><div class="search-input"><input placeholder="搜索文章（支持多关键词，请用空格分隔）"></div><div class="search-results"></div></div><script src="https://cdn.jsdelivr.net/npm/jquery@v3.4.1/dist/jquery.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.min.js"></script><script src="https://cdn.jsdelivr.net/npm/velocity-animate@1.5.2/velocity.ui.min.js"></script><script src="https://cdn.jsdelivr.net/npm/ribbon.js@latest/dist/ribbon.min.js" size="120" alpha="0.6" zIndex="-1"></script><script src="https://cdn.jsdelivr.net/gh/theme-next/theme-next-canvas-nest@latest/canvas-nest.min.js" color="1,0,0" opacity="0.6" count="99" zIndex="-1"></script><script>function initSearch() {
  var isXML = true;
  var search_path = 'search.json';

  if (!search_path) {
    search_path = 'search.xml';
  } else if (/json$/i.test(search_path)) {
    isXML = false;
  }

  var path = '/' + search_path;
  $.ajax({
    url: path,
    dataType: isXML ? 'xml' : 'json',
    async: true,
    success: function (res) {
      var datas = isXML ? $('entry', res).map(function () {
        // 将 XML 转为 JSON
        return {
          title: $('title', this).text(),
          content: $('content', this).text(),
          url: $('url', this).text()
        };
      }).get() : res;
      var $input = $('.search-input input');
      var $result = $('.search-results');
      // 搜索对象（标题、内容）的权重，影响显示顺序
      var WEIGHT = { title: 100, content: 1 };
      var searchPost = function () {
        var searchText = $input.val().toLowerCase().trim();
        // 根据空白字符分隔关键字
        var keywords = searchText.split(/[\s]+/);
        // 搜索结果
        var matchPosts = [];

        // 有多个关键字时，将原文字整个保存下来
        if (keywords.length > 1) {
          keywords.push(searchText);
        }
        // 防止未输入字符时搜索
        if (searchText.length > 0) {
          datas.forEach(function (data) {
            var isMatch  = false;
            // 没有标题的文章使用预设的 i18n 变量代替
            var title = (data.title && data.title.trim()) || '[ 文章无标题 ]';
            var titleLower = title && title.toLowerCase();
            // 删除 HTML 标签 和 所有空白字符
            var content = data.content && data.content.replace(/<[^>]+>/g, '');
            var contentLower = content && content.toLowerCase();
            // 删除重复的 /
            var postURL = data.url && decodeURI(data.url).replace(/\/{2,}/g, '/');
            // 标题中匹配到的关键词
            var titleHitSlice = [];
            // 内容中匹配到的关键词
            var contentHitSlice = [];

            keywords.forEach(function (keyword) {
              /**
              * 获取匹配的关键词的索引
              * @param {String} keyword 要匹配的关键字
              * @param {String} text 原文字
              * @param {Boolean} caseSensitive 是否区分大小写
              * @param {Number} weight 匹配对象的权重。权重大的优先显示
              * @return {Array}
              */
              function getIndexByword (word, text, caseSensitive, weight) {
                if (!word || !text) {
                  return [];
                };

                var startIndex = 0; // 每次匹配的开始索引
                var index = -1;     // 匹配到的索引值
                var result = [];    // 匹配结果

                if (!caseSensitive) {
                  word = word.toLowerCase();
                  text = text.toLowerCase();
                }

                while((index = text.indexOf(word, startIndex)) !== -1) {
                  var hasMatch = false;
                  // 索引位置相同的关键词，保留长度较长的
                  titleHitSlice.forEach(function (hit) {
                    if (hit.index === index && hit.word.length < word.length) {
                      hit.word = word;
                      hasMatch = true;
                    }
                  });
                  startIndex = index + word.length;
                  !hasMatch && result.push({ index: index, word: word, weight: weight });
                }
                return result;
              }
              titleHitSlice = titleHitSlice.concat(getIndexByword(keyword, titleLower, false, WEIGHT.title));
              contentHitSlice = contentHitSlice.concat(getIndexByword(keyword, contentLower, false, WEIGHT.content));
            });

            var hitTitle = titleHitSlice.length;
            var hitContent = contentHitSlice.length;

            if (hitTitle > 0 || hitContent > 0) {
              isMatch = true;
            }
            if (isMatch) {
              ;[titleHitSlice, contentHitSlice].forEach(function (hit) {
                // 按照匹配文字的索引的递增顺序排序
                hit.sort(function (left, right) {
                  return left.index - right.index;
                });
              });
              /**
              * 给文本中匹配到的关键词添加标记，从而进行高亮显示
              * @param {String} text 原文本
              * @param {Array} hitSlice 匹配项的索引信息
              * @param {Number} start 开始索引
              * @param {Number} end 结束索引
              * @return {String}
              */
              function highlightKeyword (text, hitSlice, start, end) {
                if (!text || !hitSlice || !hitSlice.length) {
                  return;
                }

                var result = '';
                var startIndex = start;
                var endIndex = end;
                hitSlice.forEach(function (hit) {
                  if (hit.index < startIndex) {
                    return;
                  }

                  var hitWordEnd = hit.index + hit.word.length;
                  result += text.slice(startIndex, hit.index);
                  result += '<b>' + text.slice(hit.index, hitWordEnd) + '</b>';
                  startIndex = hitWordEnd;
                });
                result += text.slice(startIndex, endIndex);
                return result;
              }

              var postData = {};
              // 文章总的搜索权重
              var postWeight = titleHitSlice.length * WEIGHT.title + contentHitSlice.length * WEIGHT.content;
              // 标记匹配关键词后的标题
              var postTitle = highlightKeyword(title, titleHitSlice, 0, title.length) || title;
              // 标记匹配关键词后的内容
              var postContent;
              // 显示内容的长度
              var SHOW_WORD_LENGTH = 200;
              // 命中关键词前的字符显示长度
              var SHOW_WORD_FRONT_LENGTH = 20;
              var SHOW_WORD_END_LENGTH = SHOW_WORD_LENGTH - SHOW_WORD_FRONT_LENGTH;

              // 截取匹配的第一个字符，前后共 200 个字符来显示
              if (contentHitSlice.length > 0) {
                var firstIndex = contentHitSlice[0].index;
                var start = firstIndex > SHOW_WORD_FRONT_LENGTH ? firstIndex - SHOW_WORD_FRONT_LENGTH : 0;
                var end = firstIndex + SHOW_WORD_END_LENGTH;
                postContent = highlightKeyword(content, contentHitSlice, start, end);
              } else { // 未匹配到内容，直接截取前 200 个字符来显示
                postContent = content.slice(0, SHOW_WORD_LENGTH);
              }
              postData.title = postTitle;
              postData.content = postContent;
              postData.url = postURL;
              postData.weight = postWeight;
              matchPosts.push(postData);
            }
          });
        }

        var resultInnerHtml = '';
        if (matchPosts.length) {
          // 按权重递增的顺序排序，使权重大的优先显示
          matchPosts.sort(function (left, right) {
            return right.weight - left.weight;
          });
          resultInnerHtml += '<ul>';
          matchPosts.forEach(function (post) {
            resultInnerHtml += '<li><a class="search-results-title" href="' + post.url + '">';
            resultInnerHtml += post.title;
            resultInnerHtml += '</a><div class="search-results-content">';
            resultInnerHtml += post.content;
            resultInnerHtml += '</div></li>';
          });
          resultInnerHtml += '</ul>';
        } else {
          resultInnerHtml += '<div class="search-results-none"><i class="far fa-meh"></i></div>';
        }
        $result.html(resultInnerHtml);
      };
      $input.on('input', searchPost);
      $input.on('keyup', function (e) {
        if (e.keyCode === Stun.utils.codeToKeyCode('Enter')) {
          searchPost();
        }
      });
    }
  });
}

function closeSearch () {
  $('body').css({ overflow: 'auto' });
  $('.search-popup').css({ display: 'none' });
  $('.search-mask').css({ display: 'none' });
}

window.addEventListener('DOMContentLoaded', function () {
  Stun.utils.pjaxReloadLocalSearch = function () {
    $('.header-nav-search').on('click', function (e) {
      e.stopPropagation();
      $('body').css('overflow', 'hidden');
      $('.search-popup')
        .velocity('stop')
        .velocity('transition.expandIn', {
          duration: 300,
          complete: function () {
            $('.search-popup input').focus();
          }
        });
      $('.search-mask')
        .velocity('stop')
        .velocity('transition.fadeIn', {
          duration: 300
        });

      initSearch();
    });
    $('.search-mask, .search-close').on('click', function () {
      closeSearch();
    });
    $(document).on('keydown', function (e) {
      // Escape <=> 27
      if (e.keyCode === Stun.utils.codeToKeyCode('Escape')) {
        closeSearch();
      }
    });
  };

  Stun.utils.pjaxReloadLocalSearch();
}, false);</script><script src="https://cdn.jsdelivr.net/npm/gitalk@latest/dist/gitalk.min.js"></script><script src="https://cdn.jsdelivr.net/npm/js-md5@latest/src/md5.min.js"></script><script>function loadGitalk () {
  if (!document.getElementById('gitalk-container')) {
    return;
  }

  var gitalk = new Gitalk({
    id: md5(window.location.pathname.slice(1)),
    clientID: '6ca09daabba4f7147cee',
    clientSecret: 'ded593f333a1a88bfb1a5e39e8227c3afc71e08f',
    repo: 'sunyubk.github.io',
    owner: 'sunyubk',
    admin: ['sunyubk'],
    distractionFreeMode: 'true',
    language: 'zh-CN'
  });
  gitalk.render('gitalk-container');
}

if (false) {
  loadGitalk();
} else {
  window.addEventListener('DOMContentLoaded', loadGitalk, false);
}</script><script src="/js/utils.js?v=2.0.0-rc.0"></script><script src="/js/stun-boot.js?v=2.0.0-rc.0"></script><script src="/js/scroll.js?v=2.0.0-rc.0"></script><script src="/js/header.js?v=2.0.0-rc.0"></script><script src="/js/sidebar.js?v=2.0.0-rc.0"></script><script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"jsonPath":"/live2dw/assets/shizuku.model.json"},"display":{"position":"left","width":250,"height":500},"mobile":{"show":false},"log":false});</script></body></html>